/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.devs.benchmark.topology;

import java.util.List;
import org.devs.benchmark.Util;
import org.devs.benchmark.modeling.ConnectionType;
import org.devs.benchmark.modeling.CoupledType;
import org.devs.benchmark.modeling.ModelType;

/**
 *
 * @author Alejandro Moreno
 */
public class TridMesh extends Network {

    int depth;
    int width;
    int height;

    public TridMesh(String name, int width, int height, int depth, Class message) throws Exception {

        super(name, message);

        if (width < 1 || height < 1 || depth < 1) {
            throw new Exception("Parameters are incorrect");
        }

        this.depth = depth;
        this.width = width;
        this.height = height;

    }

    public TridMesh(String name, int width, int height, int depth, Class message, int recursion) throws Exception {

        super(name, message, recursion);

        if (width < 1 || height < 1 || recursion < 1 || depth < 1) {
            throw new Exception("Parameters are incorrect");
        }

        this.depth = depth;
        this.width = width;
        this.height = height;

    }

    public int getDepth() {
        return depth;
    }

    public void setDepth(int depth) {
        this.depth = depth;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }



    public void buildModel() {

        super.setModel(this.createNetwork(this.name, this.width, this.height, this.depth, super.message, super.recursion));
    }

    public void connectSructs(CoupledType coupled, int width, int height, int depth, List<List<ModelType>> structs) {


        for (int j = 0; j < (width * height); j++) {

            for (int i = 0; i < (structs.size() - 1); i++) {
                int q = (i + 1);

                List<ModelType> struct1 = structs.get(i);
                List<ModelType> struct2 = structs.get(q);

                System.out.println(struct1.size());

                System.out.println(struct1.get(j).getName());
                System.out.println(struct2.get(j).getName());
                coupled.getConnections().add(new ConnectionType(struct1.get(j), struct1.get(j).getOutports().get(4), struct2.get(j), struct2.get(j).getInports().get(5)));
                coupled.getConnections().add(new ConnectionType(struct2.get(j), struct2.get(j).getOutports().get(5), struct1.get(j), struct1.get(j).getInports().get(4)));


            }
        }

    }

    public void connectNodes(CoupledType coupled, int width, int height, int depth) {

        if (coupled.getModels().size() > 0) {

            for (int i = 0; i < 6; i++) {

                addConnectionToParent(coupled, 0, i, i);
                addConnectionFromParent(coupled, 0, i, i);

            }

            List<List<ModelType>> structs = Util.partition(coupled.getModels(), width * height);

            connectSructs(coupled, width, height, depth, structs);

            for (int q = 0; q < depth; q++) {

                List<ModelType> models = structs.get(q);



                for (int i = 0; i < (models.size() - 1); i++) {

                    int j = (i + 1);
                    if (j % width != 0) {

                        coupled.getConnections().add(new ConnectionType(models.get(i), models.get(i).getOutports().get(1), models.get(j), models.get(j).getInports().get(3)));
                        coupled.getConnections().add(new ConnectionType(models.get(j), models.get(j).getOutports().get(3), models.get(i), models.get(i).getInports().get(1)));

                    }
                    int k = (i + width);

                    if (k < models.size()) {

                        coupled.getConnections().add(new ConnectionType(models.get(i), models.get(i).getOutports().get(2), models.get(k), models.get(k).getInports().get(0)));
                        coupled.getConnections().add(new ConnectionType(models.get(k), models.get(k).getOutports().get(0), models.get(i), models.get(i).getInports().get(2)));

                    }

                }
            }

        }


    }

    public ModelType createNetwork(String name, int width, int height, int depth, Class message, int recursion) {
        return create(name, width, height, depth, message, "", recursion);
    }

    public ModelType create(String name, int width, int height, int depth, Class message, String id, int recursion) {

        CoupledType coupled = null;

        if (recursion > 0) {

            coupled = new CoupledType(name + "_Coupled" + id, Util.createInports(6, message), Util.createOutports(6, message));

            for (int k = 0; k < depth; k++) {

                for (int j = 0; j < height; j++) {

                    for (int i = 0; i < width; i++) {
                        coupled.getModels().add(create(name, width, height, depth, message, id + "_" + k + "_" + j + "_" + i, recursion - 1));

                    }


                }
            }

            connectNodes(coupled, width, height, depth);

        } else {


            coupled = buildNode(name, 6, message, id);


        }

        return coupled;

    }
}
